package com.demo2do.fms.admin.service.supplier.impl;

import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;

import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.io.FilenameUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.math.NumberUtils;
import org.apache.commons.lang3.time.DateUtils;
import org.apache.poi.ss.usermodel.DataFormatter;
import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.ss.usermodel.Sheet;
import org.apache.poi.ss.usermodel.Workbook;
import org.apache.poi.ss.usermodel.WorkbookFactory;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;

import com.demo2do.core.entity.exception.BusinessException;
import com.demo2do.core.entity.page.Page;
import com.demo2do.core.persistence.GenericDaoSupport;
import com.demo2do.core.persistence.annotation.Dao;
import com.demo2do.core.utils.DateFormatUtils;
import com.demo2do.fms.admin.Constants;
import com.demo2do.fms.admin.dao.data.MasterDataDao;
import com.demo2do.fms.admin.dao.supplier.DriverDao;
import com.demo2do.fms.admin.dao.supplier.EsbBlackWhiteListDao;
import com.demo2do.fms.admin.dao.supplier.EsbBlackWhiteListScoreDao;
import com.demo2do.fms.admin.dao.supplier.OrganizationDao;
import com.demo2do.fms.admin.dao.supplier.SupplierDao;
import com.demo2do.fms.admin.dao.vam.DriverLineDao;
import com.demo2do.fms.admin.dao.vehicle.VehicleDao;
import com.demo2do.fms.admin.entity.export.supplier.DriverSheet;
import com.demo2do.fms.admin.entity.search.supplier.DriverAuditSearch;
import com.demo2do.fms.admin.entity.search.supplier.DriverSearch;
import com.demo2do.fms.admin.entity.security.Login;
import com.demo2do.fms.admin.entity.upload.UploadResult;
import com.demo2do.fms.admin.entity.vam.DriverStat;
import com.demo2do.fms.admin.handler.FileHandler;
import com.demo2do.fms.admin.handler.support.FileStorage;
import com.demo2do.fms.admin.service.supplier.DriverService;
import com.demo2do.fms.admin.utils.DateParseUtils;
import com.demo2do.fms.entity.authority.Organization;
import com.demo2do.fms.entity.driver.Dismiss;
import com.demo2do.fms.entity.driver.Driver;
import com.demo2do.fms.entity.driver.DriverAuditStatus;
import com.demo2do.fms.entity.driver.DriverDuty;
import com.demo2do.fms.entity.driver.DriverEvent;
import com.demo2do.fms.entity.driver.DriverEventType;
import com.demo2do.fms.entity.driver.EsbBlackWhiteList;
import com.demo2do.fms.entity.driver.EsbBlackWhiteListScore;
import com.demo2do.fms.entity.supplier.common.Supplier;
import com.demo2do.fms.entity.vam.DriverLine;
import com.demo2do.fms.entity.vehicle.source.Vehicle;

/**
 *
 * @author Ark
 *
 */
@Service("driverService")
public class DriverServiceImpl implements DriverService {
    
    private static final Logger logger = LoggerFactory.getLogger(DriverServiceImpl.class);
    
    @Autowired
    private GenericDaoSupport genericDaoSupport;
    
    @Dao
    private DriverDao driverDao;
    
    @Dao
    private OrganizationDao organizationDao;
    
    @Dao
    private SupplierDao supplierDao;
    
    @Dao
    private VehicleDao vehicleDao;
    
    @Dao
    private MasterDataDao masterDataDao;
    
    @Autowired
    private FileHandler fileHandler;
    
    @Dao
    private DriverLineDao driverLineDao;
    
    @Dao
    private EsbBlackWhiteListDao esbBlackWhiteListDao;
    
    @Dao
    private EsbBlackWhiteListScoreDao esbBlackWhiteListScoreDao;
    
    /*
     * (non-Javadoc)
     * @see com.demo2do.fms.admin.service.supplier.DriverService#count(com.demo2do.fms.admin.entity.security.Login)
     */
    public int count(Login login) {
        if (login.isSupplier()) {
            return driverDao.count(login.getSupplierId());
        } else {
            return driverDao.count();
        }
    }
    
    /* (non-Javadoc)
     * @see com.demo2do.fms.admin.service.supplier.DriverService#count(com.demo2do.fms.admin.entity.security.Login, boolean)
     */
    public int count(Login login, DriverAuditStatus status, boolean bind) {
    	
        if (login.isSupplier()) {
            return driverDao.count(login.getSupplierId(), status, bind);
        } else {
            return driverDao.count(status, bind);
        }
        
    }
    
    /* (non-Javadoc)
     * @see com.demo2do.fms.admin.service.supplier.DriverService#count(com.demo2do.fms.admin.entity.security.Login, com.demo2do.fms.entity.driver.DriverAuditStatus)
     */
    public int count(Login login, DriverAuditStatus status) {
        
        if (login.isSupplier()) {
            return driverDao.count(login.getSupplierId(), status);
        } else {
            return driverDao.count(status);
        }
        
    }
    
    /*
     * (non-Javadoc)
     * @see com.demo2do.fms.admin.service.supplier.DriverService#count(java.util.List)
     */
    public int count(List<Long> supplierIds) {
        if (CollectionUtils.isEmpty(supplierIds)) {
            return 0;
        }
        return driverDao.count(supplierIds);
    }
    
    /*
     * (non-Javadoc)
     * @see com.demo2do.fms.admin.service.supplier.DriverService#count(java.util.List, com.demo2do.fms.entity.driver.DriverAuditStatus)
     */
    public int count(List<Long> supplierIds, DriverAuditStatus status) {
        
        if (CollectionUtils.isEmpty(supplierIds)) {
            return 0;
        }
        
        return driverDao.count(supplierIds, status);
        
    }
    
    /* (non-Javadoc)
     * @see com.demo2do.fms.admin.service.supplier.DriverService#count(com.demo2do.fms.admin.entity.search.supplier.DriverSearch)
     */
    public int count(DriverSearch search) {
        String sentence = search.buildSentenceTemplate();
        Map<String, Object> parameters = search.buildParameters();
        return genericDaoSupport.count(sentence, parameters);
    }
    
    /*
     * (non-Javadoc)
     * @see com.demo2do.fms.admin.service.supplier.DriverService#count(com.demo2do.fms.admin.entity.search.supplier.DriverAuditSearch)
     */
    public int count(DriverAuditSearch search) {
        
        String sentence = search.buildSentenceTemplate();
        Map<String, Object> parameters = search.buildParameters();
        
        return genericDaoSupport.count(sentence, parameters);
        
    }
    
    /*
     * (non-Javadoc)
     * @see com.demo2do.fms.admin.service.supplier.DriverService#list(com.demo2do.fms.admin.entity.security.Login, com.demo2do.core.entity.page.Page)
     */
    public List<Driver> list(Login login, Page page) {
        
        page.calculate();
        
        if (login.isSupplier()) {
            return driverDao.list(login.getSupplierId(), page.getBeginIndex(), page.getEveryPage());
        } else {
            return driverDao.list(page.getBeginIndex(), page.getEveryPage());
        }
        
    }
    
    /* (non-Javadoc)
     * @see com.demo2do.fms.admin.service.supplier.DriverService#list(com.demo2do.fms.admin.entity.security.Login, boolean, com.demo2do.core.entity.page.Page)
     */
    public List<Driver> list(Login login, DriverAuditStatus status, boolean bind, Page page) {
        
        page.calculate();
        
        if (login.isSupplier()) {
            return driverDao.list(login.getSupplierId(), status, bind, page.getBeginIndex(), page.getEveryPage());
        } else {
            return driverDao.list(status, bind, page.getBeginIndex(), page.getEveryPage());
        }
        
    }

    /* (non-Javadoc)
     * @see com.demo2do.fms.admin.service.supplier.DriverService#list(com.demo2do.fms.admin.entity.security.Login, com.demo2do.fms.entity.driver.DriverAuditStatus, com.demo2do.core.entity.page.Page)
     */
    public List<Driver> list(Login login, DriverAuditStatus status, Page page) {
        
    	page.calculate();
        
        if (login.isSupplier()) {
            return driverDao.list(login.getSupplierId(), status, page.getBeginIndex(), page.getEveryPage());
        } else {
            return driverDao.list(status, page.getBeginIndex(), page.getEveryPage());
        }
        
    }
    
    /*
     * (non-Javadoc)
     * @see com.demo2do.fms.admin.service.supplier.DriverService#list(java.lang.Long, com.demo2do.fms.entity.driver.DriverAuditStatus)
     */
    public List<Driver> list(Long supplierId, DriverAuditStatus status) {
        return driverDao.list(supplierId, status);
    }
    
    /*
     * (non-Javadoc)
     * @see com.demo2do.fms.admin.service.supplier.DriverService#list(java.lang.String, com.demo2do.fms.entity.driver.DriverAuditStatus)
     */
    public List<Driver> list(String vehicleCode, DriverAuditStatus status) {
        
        if(StringUtils.isEmpty(vehicleCode)) {
            return null;
        }
        
        Vehicle vehicle = vehicleDao.loadByCode(vehicleCode);
        
        if(vehicle == null) {
            return null;
        } else {
            return driverDao.listByVehicle(vehicle.getId(), status);
        }
        
    }
    
    /*
     * (non-Javadoc)
     * @see com.demo2do.fms.admin.service.supplier.DriverService#list(com.demo2do.fms.entity.driver.DriverAuditStatus)
     */
    public List<Driver> list(DriverAuditStatus status) {
        return driverDao.list(status);
    }
    
    /* (non-Javadoc)
     * @see com.demo2do.fms.admin.service.supplier.DriverService#list(com.demo2do.fms.admin.entity.search.supplier.DriverSearch, com.demo2do.core.entity.page.Page)
     */
    @SuppressWarnings("unchecked")
    public List<Driver> list(DriverSearch search, Page page) {
        
        // 1. build sentence
        String sentence = search.buildSentenceTemplate();
        Map<String, Object> parameters = search.buildParameters();
        
        // 2. do query
        List<Driver> drivers = genericDaoSupport.searchForList(sentence, parameters, page.getBeginIndex(), page.getEveryPage());
        page.calculate();
        return drivers;
        
    }
    
    /*
     * (non-Javadoc)
     * @see com.demo2do.fms.admin.service.supplier.DriverService#search(com.demo2do.fms.admin.entity.search.supplier.DriverAuditSearch, com.demo2do.core.entity.page.Page)
     */
    @SuppressWarnings("unchecked")
    public List<Driver> search(DriverAuditSearch search, Page page) {
        
        // 1. build sentence
        String sentence = search.buildSentenceTemplate();
        Map<String, Object> parameters = search.buildParameters();
        
        // 2. do query
        List<Driver> drivers = genericDaoSupport.searchForList(sentence, parameters, page.getBeginIndex(), page.getEveryPage());
        page.calculate();
        return drivers;
        
    }
    
    /* (non-Javadoc)
     * @see com.demo2do.fms.admin.service.supplier.DriverService#export(java.util.List)
     */
    @SuppressWarnings("unchecked")
	public List<DriverSheet> export(DriverSearch search) {
    	
    	// 1. list drivers
    	String sentence = search.buildSentenceTemplate();
        Map<String, Object> parameters = search.buildParameters();
    	List<Driver> drivers = genericDaoSupport.searchForList(sentence, parameters);
    	
    	// 2. construct driverSheet
    	List<DriverSheet> sheets = this.parseDriverSheet(drivers);
    	return sheets;
    	
    }
    
    /**
     * @param drivers
     * @return
     */
    private List<DriverSheet> parseDriverSheet(List<Driver> drivers) {
    	
    	List<DriverSheet> sheets = new ArrayList<DriverSheet>();
    	for (Driver driver : drivers) {
    		
    		String gender = null;	// 性别
            if (StringUtils.equalsIgnoreCase("60", driver.getGender())) {
                gender = "男";
            } else if (StringUtils.equals("61", driver.getGender())) {
                gender = "女";
            }
            
            String vehicleInfo = "";		// 驳运车代码 + 驳运车英文车牌号 + 驳运车中文车牌号
            if (driver.isBind()) {
                if (driver.getVehicleId() != null) {
                    Vehicle vehicle = genericDaoSupport.get(Vehicle.class, driver.getVehicleId());
                    if (vehicle != null) {
                        vehicleInfo = vehicle.getCode() + " - " + vehicle.getName();
                    }
                }
            }
            
            String contractParty = null;		// 劳务合同签署方
            if (StringUtils.equals("01", driver.getContractParty())) {
            	contractParty = "公司";
            } else if (StringUtils.equals("02", driver.getContractParty())) {
            	contractParty = "中介";
            }
            
            Map<String, String> drivingTypes = new HashMap<String, String>();	// 准驾车型
            drivingTypes.put("01", "A1");
            drivingTypes.put("02", "A2");
            drivingTypes.put("03", "B2");
            drivingTypes.put("04", "B1");
            drivingTypes.put("05", "C1");
            String drivingType = drivingTypes.get(driver.getDrivingType());
            
            String educationLevel = driver.getEducationLevel() != null ? masterDataDao.get("EDUCATION", driver.getEducationLevel()) : null;	// 文化程度
            String clan = driver.getClanId() != null ? masterDataDao.get("PARTY", driver.getClanId()) : null;			// 政治面貌
            String degree = driver.getDegreeId() != null ? masterDataDao.get("DEGREE", driver.getDegreeId()) : null;		// 学位
			sheets.add(new DriverSheet(driver, gender, vehicleInfo, contractParty, drivingType, educationLevel, clan, degree, driver.getBlack(), driver.getScore()));
			
		}
    	
    	return sheets;
    	
    }
    
    /*
     * (non-Javadoc)
     * @see com.demo2do.fms.admin.service.supplier.DriverService#list(java.util.List, com.demo2do.core.entity.page.Page)
     */
    public List<Driver> list(List<Long> supplierIds, Page page) {
        List<Driver> result = driverDao.list(supplierIds, page.getBeginIndex(), page.getEveryPage());
        page.calculate();
        return result;
    }
    
    /*
     * (non-Javadoc)
     * @see com.demo2do.fms.admin.service.supplier.DriverService#list(java.util.List, com.demo2do.fms.entity.driver.DriverAuditStatus, com.demo2do.core.entity.page.Page)
     */
    public List<Driver> list(List<Long> supplierIds, DriverAuditStatus status, Page page) {
        List<Driver> result = driverDao.list(supplierIds, status, page.getBeginIndex(), page.getEveryPage());
        page.calculate();
        return result;
    }
    
    /* (non-Javadoc)
     * @see com.demo2do.fms.admin.service.supplier.DriverService#load(java.lang.Long)
     */
    public Driver load(Long id) {
        return genericDaoSupport.load(Driver.class, id);
    }
    
    /* (non-Javadoc)
     * @see com.demo2do.fms.admin.service.supplier.DriverService#load(java.lang.String, com.demo2do.fms.entity.driver.DriverAuditStatus)
     */
    public Driver load(Long supplierId, String code, DriverAuditStatus status) {
        if (supplierId == null) {
            return driverDao.load(code, status);
        } else {
            return driverDao.load(code, supplierId, status);
        }
    }
    
    /* (non-Javadoc)
     * @see com.demo2do.fms.admin.service.supplier.DriverService#existCode(java.lang.String)
     */
    public Map<String, Object> existCode(String code) {
        
        Map<String, Object> result = new HashMap<String, Object>();
        
        // 1. load driver
        Driver driver = driverDao.loadByCode(code);
        result.put("existed", driver != null);
        
        // 2. construct message
        if (driver == null) {
            
            String message = "该工号有效";
            result.put("message", message);
            
        } else {
            
            Supplier supplier = driver.getSupplier();
            String message = "该工号已存在！所属供方=" + supplier.getShortName() + "! 司机姓名=" + driver.getName();
            result.put("message", message);
            
        }
        
        return result;
        
    }
    
    /* (non-Javadoc)
     * @see com.demo2do.fms.admin.service.supplier.DriverService#existCitizen(java.lang.String)
     */
    public Map<String, Object> existCitizen(String citizenCode) {

        citizenCode = citizenCode.trim().toUpperCase();

        Map<String, Object> result = new HashMap<String, Object>();
        
        // 1. load driver
        Driver driver = driverDao.loadByCitizen(citizenCode);
        result.put("existed", driver != null);
        
        // 2. construct message
        if (driver == null) {
            
            String message = "该身份证号有效";
            result.put("message", message);
            
        } else {
            
            Supplier supplier = driver.getSupplier();
            String message = "该身份证号已被使用！所属供方=" + supplier.getShortName() + "! 司机姓名=" + driver.getName(); 
            result.put("message", message);
            
        }
        
        return result;
        
    }
    
    /* (non-Javadoc)
     * @see com.demo2do.fms.admin.service.supplier.DriverService#existMobile(java.lang.String)
     */
    public Map<String, Object> existMobile(String mobile) {
        
        Map<String, Object> result = new HashMap<String, Object>();
        
        // 1. load driver
        Driver driver = driverDao.loadByMobile(mobile);
        result.put("existed", driver != null);
        
        // 2. construct message
        if (driver == null) {
            
            String message = "该手机号有效";
            result.put("message", message);
            
        } else {
            
            Supplier supplier = driver.getSupplier();
            String message = "该手机号已被使用！所属供方=" + supplier.getShortName() + "! 司机姓名=" + driver.getName(); 
            result.put("message", message);
            
        }
        
        return result;
        
    }
    
    /* (non-Javadoc)
     * @see com.demo2do.fms.admin.service.supplier.DriverService#existBrand(java.lang.String)
     */
    public List<DriverStat> listByBrand(String brandCNCode) {
        
        // 1. search vehicle
        Vehicle vehicle = vehicleDao.loadByBrandCNCode(brandCNCode);
        if (vehicle == null) {
            throw BusinessException.newInstance("500", "车辆不存在");
        }
        
        // 2. search driver
        List<Driver> drivers = driverDao.listByVehicle(vehicle.getId());
        List<DriverStat> driverStats = new LinkedList<DriverStat>();
        for (Driver driver : drivers) {
            DriverStat driverStat = new DriverStat(driver);
            driverStats.add(driverStat);
        }
        
        return driverStats;
        
    }
    
    /* (non-Javadoc)
     * @see com.demo2do.fms.admin.service.supplier.DriverService#listByBrand(java.util.List)
     */
    public List<DriverLine> listByBrand(List<String> brandCNCodes) {
        return driverLineDao.list(brandCNCodes);
    }
    
    /* (non-Javadoc)
     * @see com.demo2do.fms.admin.service.supplier.DriverService#create(com.demo2do.fms.entity.driver.Driver, java.lang.Long)
     */
    public void create(Driver driver, Login login) {
        
        // 1. check unique_field
        int existCount = driverDao.countByCode(driver.getCode());
        if (existCount > 0) {
            throw BusinessException.newInstance("400", "该工号已存在，创建失败!");
        }
        
        existCount = driverDao.countByCitizen(driver.getCitizenCode());
        if (existCount > 0) {
            throw BusinessException.newInstance("400", "该身份证号已存在，创建失败!");
        }
        
        existCount = driverDao.countByMobile(driver.getMp());
        if (existCount > 0) {
            throw BusinessException.newInstance("400", "该手机号已存在，创建失败!");
        }
        
        // 2. save driver
        Supplier supplier = supplierDao.loadSupplier(login.getSupplierId());
        Organization organization = genericDaoSupport.load(Organization.class, supplier.getOrgId());
        genericDaoSupport.save(driver.initialize(supplier, organization, login.getId()));
        
        // 4. update score and isBlack
        EsbBlackWhiteList esbBlackWhiteList = esbBlackWhiteListDao.findLastByCitizenCode(driver.getCitizenCode());
        
        if (esbBlackWhiteList != null && esbBlackWhiteList.getBlack() != null) {
            
            driver.updateBlack(esbBlackWhiteList.getBlack());
        }
        
        EsbBlackWhiteListScore blackWhiteListScore = esbBlackWhiteListScoreDao.findLastByCitizenCode(driver.getCitizenCode());
        
        if (blackWhiteListScore != null && blackWhiteListScore.getScore() != null) {
            
            driver.updateScore(blackWhiteListScore.getScore());
        }
        
        // 3. save driver_event
        genericDaoSupport.save(new DriverEvent(driver, DriverEventType.CREATE, login.getId()));
        
    }
    
    /* (non-Javadoc)
     * @see com.demo2do.fms.admin.service.supplier.DriverService#upload(com.demo2do.fms.admin.entity.security.Login, org.springframework.web.multipart.MultipartFile)
     */
    @SuppressWarnings("unchecked")
    public List<UploadResult> upload(Login login, MultipartFile file) {
        
        try {
            
            // 1. save file
            FileStorage fileStorage = new FileStorage("driver/upload", Constants.DRIVER_BATCH_UPLOAD, FilenameUtils.getExtension(file.getOriginalFilename()));
            fileHandler.save(fileStorage, file.getInputStream());
            
            // 2. parse file to drivers
            Map<String, Object> result  = this.parse(login, file);
            
            // 3. save driver_info
            List<Driver> drivers = (List<Driver>) result.get("drivers");
            for (Driver driver : drivers) {
                
                // 3.1 save driver
                genericDaoSupport.save(driver);
                
                // 3.2 save driver_event
                genericDaoSupport.save(new DriverEvent(driver, DriverEventType.CREATE, login.getId()));
                
            }
            
            logger.trace("#upload() - batch upload success");
            return (List<UploadResult>) result.get("uploadResults");
            
        } catch (Exception e) {
            logger.error("#upload() - batch upload driver fail, exception is [{}]", e);
            throw BusinessException.newInstance("500", "批量上传失败，" + e.getMessage());
        }
        
    }
    
    /* (non-Javadoc)
     * @see com.demo2do.fms.admin.service.supplier.DriverService#delete(java.lang.Long)
     */
    public void delete(Long id, Long operator) {

        // 1. delete driver
        Driver driver = genericDaoSupport.load(Driver.class, id);
        genericDaoSupport.update(driver.disable(operator));
        
        // 2. save driver_event
        genericDaoSupport.save(new DriverEvent(driver, DriverEventType.DELETE, operator));
        
    }
    
    /*
     * (non-Javadoc)
     * @see com.demo2do.fms.admin.service.supplier.DriverService#audit(com.demo2do.fms.entity.driver.Driver, com.demo2do.fms.admin.entity.security.Login)
     */
    public void audit(Driver driver, Login login) {
        
        // 1. validate
        String inValidMessage = driver.couldAudit();
        if(StringUtils.isNotBlank(inValidMessage)) {
            throw new BusinessException("递交审核失败、" + inValidMessage);
        }
        
        // 2. update driver
        genericDaoSupport.update(driver.audit(login.getId()));
        
        // 3. save driver event
        genericDaoSupport.save(new DriverEvent(driver, DriverEventType.AUDIT, login.getId()));
        
    }
    
    /* (non-Javadoc)
     * @see com.demo2do.fms.admin.service.supplier.DriverService#batchAudit(java.util.List, com.demo2do.fms.admin.entity.security.Login)
     */
    public Map<String, Integer> batchAudit(List<Long> driverIds, Login login) {
        
        Map<String, Integer> result = new HashMap<String, Integer>();
        
        Long operator = login.getId();
        List<Driver> drivers = driverDao.list(driverIds);
        
        // 1. do batch audit
        int successNumber = 0;
        int failNumber = 0;
        
        for (Driver driver : drivers) {
            
            if (StringUtils.isNotBlank(driver.couldAudit())) {
                failNumber++;
                continue;
            }
            
            // audit driver
            genericDaoSupport.update(driver.audit(operator));
            successNumber++;
            
            // save driver_event
            genericDaoSupport.save(new DriverEvent(driver, DriverEventType.AUDIT, operator));
            
        }
        
        // 2. construct result
        result.put("successNumber", successNumber);
        result.put("failNumber", failNumber);
        
        return result;
        
    }
    
    /* (non-Javadoc)
     * @see com.demo2do.fms.admin.service.supplier.DriverService#adopt(com.demo2do.fms.entity.driver.Driver, java.lang.Long)
     */
    public void adopt(Driver driver, Long operator) {
        
        // 1. adopt driver
        genericDaoSupport.update(driver.adopt(operator));
        
        // 2. save driver_event
        genericDaoSupport.save(new DriverEvent(driver, DriverEventType.ADOPT, operator));
        
    }
    
    /* (non-Javadoc)
     * @see com.demo2do.fms.admin.service.supplier.DriverService#reject(com.demo2do.fms.entity.driver.Driver, java.lang.Long)
     */
    public void reject(Driver driver, Long operator) {
        
        // 1. reject driver
        genericDaoSupport.update(driver.reject(operator));
        
        // 2. save driver_event
        genericDaoSupport.save(new DriverEvent(driver, DriverEventType.REJECT, operator));
        
    }
    
    /* (non-Javadoc)
     * @see com.demo2do.fms.admin.service.supplier.DriverService#quit(com.demo2do.fms.entity.driver.Driver, com.demo2do.fms.admin.entity.security.Login)
     */
    public void quit(Driver driver, Login login) {
        
        Date now = new Date();
        
        // 1. driver dismiss
        genericDaoSupport.update(driver.quit(login.getId()));
        
        // 2. save dismiss
        Dismiss dismiss = new Dismiss(driver.getName(), driver.getCitizenCode(), now);
        genericDaoSupport.save(dismiss);
        
        // 3. save driver_event
        genericDaoSupport.save(new DriverEvent(driver, DriverEventType.DISMISS, login.getId()));
        
    }
    
	/* (non-Javadoc)
	 * @see com.demo2do.fms.admin.service.supplier.DriverService#editBasic(com.demo2do.fms.entity.driver.Driver, java.lang.Long)
	 */
	public void editBasic(Driver driver, Long operator) {
	    
		// 1. check unique field
		this.checkUniqueField(driver);
		
        Driver load = genericDaoSupport.load(Driver.class, driver.getId());
		
		// 3. update score and isBlack
        EsbBlackWhiteList esbBlackWhiteList = esbBlackWhiteListDao.findLastByCitizenCode(driver.getCitizenCode());
        
        if (esbBlackWhiteList != null && esbBlackWhiteList.getBlack() != null) {
            
            load.updateBlack(esbBlackWhiteList.getBlack());
        }
        
        EsbBlackWhiteListScore blackWhiteListScore = esbBlackWhiteListScoreDao.findLastByCitizenCode(driver.getCitizenCode());
        
        if (blackWhiteListScore != null && blackWhiteListScore.getScore() != null) {
            
            load.updateScore(blackWhiteListScore.getScore());
        }
        
        load.updateBasic(driver, operator, new Date());
        
		// 2. edit driver
		genericDaoSupport.update(load);;
		
	}
	
	/**
	 * check unique field for driver
	 * 
	 * @param driver
	 */
	private void checkUniqueField(Driver driver) {
		
		Long driverId = driver.getId();
		
		// 1. check citizen code
		Driver existDriver = driverDao.loadByCitizen(driver.getCitizenCode());
		if (existDriver != null && !driverId.equals(existDriver.getId())) {
			throw BusinessException.newInstance("400", "该身份证号已存在");
		}
		
		// 2. check code 
		existDriver = driverDao.loadByCode(driver.getCode());
		if (existDriver != null && !driverId.equals(existDriver.getId())) {
			throw BusinessException.newInstance("400", "该司机工号已存在");
		}
		
		// 3. check mobile
		existDriver = driverDao.loadByMobile(driver.getMp());
		if (existDriver != null && !driverId.equals(existDriver.getId())) {
			throw BusinessException.newInstance("400", "该手机号号已存在");
		}
		
	}
	
	/* (non-Javadoc)
	 * @see com.demo2do.fms.admin.service.supplier.DriverService#editProfile(com.demo2do.fms.entity.driver.Driver)
	 */
	public void editProfile(Driver driver) {
		genericDaoSupport.update(driver);
	}
	
    /**
     * @param login
     * @param file
     * @return
     */
    private Map<String, Object> parse(Login login, MultipartFile file) {
        
        // 0. prepare data
        Map<String, Object> result = new HashMap<String, Object>();
        List<Driver> drivers = new ArrayList<Driver>();
        List<UploadResult> uploadResults = new ArrayList<UploadResult>();
        
        DataFormatter formatter = new DataFormatter();
        Date now = new Date();
        
        Long supplierId = login.getSupplierId();
        Supplier supplier = supplierDao.loadSupplier(supplierId);
        Organization organization = genericDaoSupport.load(Organization.class, supplier.getOrgId());
        
        Map<String, String> drivingTypes = new HashMap<String, String>();
        drivingTypes.put("A1", "01");
        drivingTypes.put("A2", "02");
        drivingTypes.put("B2", "03");
        drivingTypes.put("B1", "04");
        drivingTypes.put("C1", "05");
        
        try {
            
            logger.trace("#parse() - Starting parsing upload file.");

            // 1. get workbook
            Workbook workbook = WorkbookFactory.create(file.getInputStream());
            
            // 2. get sheet and rows
            Sheet sheet = workbook.getSheetAt(0);
            Iterator<Row> rows = sheet.iterator();
            
            // 3. construct drivers and uploadResults
            while (rows.hasNext()) {
                
                Row row = rows.next();
                int rowNum = row.getRowNum();
                UploadResult uploadResult = new UploadResult();
                
                if (rowNum <= 3) {
                    continue;
                }

                String name = formatter.formatCellValue(row.getCell(0));        // 姓名
                if (StringUtils.isBlank(name)) {		// 判断Excel为空行的情况
                	continue;
                }
                
                String genderText = formatter.formatCellValue(row.getCell(1));  // 性别
                String gender = null;
                if (StringUtils.equalsIgnoreCase("男", genderText)) {
                    gender = "60";
                } else if (StringUtils.equals("女", genderText)) {
                    gender = "61";
                }
                
                String code = formatter.formatCellValue(row.getCell(2));        // 工号
                String citizenCode = formatter.formatCellValue(row.getCell(3)); // 身份证号
                
                String birthdayText = formatter.formatCellValue(row.getCell(4));    // 出生日期
                if (!DateParseUtils.validDate(birthdayText, Constants.DATE_YYYYMMDD) || !StringUtils.equals(birthdayText, DateFormatUtils.format(com.demo2do.core.utils.DateUtils.parseDate(birthdayText, "yyyyMMdd"), "yyyyMMdd"))) {
                    uploadResult = new UploadResult(rowNum, "出生日期格式不对");
                    uploadResults.add(uploadResult);
                    continue;
                }
                Date birthday = DateUtils.parseDate(birthdayText, Constants.DATE_YYYYMMDD);
                
                String mp = formatter.formatCellValue(row.getCell(5));          // 手机号码
                
                String dutyText = formatter.formatCellValue(row.getCell(6));        // 职务
                DriverDuty duty = DriverDuty.descriptionOf(dutyText);
                Long dutyId = duty != null ? duty.getId() : null;
                
                String drivingAgeText = formatter.formatCellValue(row.getCell(7));  // 驾龄
                if (!NumberUtils.isCreatable(drivingAgeText) || !drivingAgeText.matches("[0-9]+")) {
                    uploadResult = new UploadResult(rowNum, "司机驾龄格式不对");
                    uploadResults.add(uploadResult);
                    continue;
                }
                Long drivingAge = Long.valueOf(drivingAgeText);
                
                String contractPartyText = formatter.formatCellValue(row.getCell(8));   //劳务合同签署方
                String contractParty = null;
                if (StringUtils.equals("公司", contractPartyText)) {
                    contractParty = "01";
                } else if (StringUtils.equals("中介", contractPartyText)) {
                    contractParty = "02";
                }
                
                String drivingTypeText = formatter.formatCellValue(row.getCell(9));  // 准驾车型
                String drivingType = drivingTypes.get(drivingTypeText);
                
                // 4.1 check required field
                Driver driver = new Driver(supplier, organization, name, gender, code, citizenCode, birthday, mp, dutyId, drivingAge, contractParty, drivingType, now, login.getId());
                uploadResult = this.checkRequiredField(rowNum, driver);
                if (uploadResult != null) {
                    uploadResults.add(uploadResult);
                    continue;
                }
                
                // 4.2 check unique field
                uploadResult = this.checkUniqueField(driver, rowNum);
                if (uploadResult != null) {
                    uploadResults.add(uploadResult);
                    continue;
                }
                
            	drivers.add(driver);
                
            }
            
            logger.trace("#parse() - Finishing parsing file with {} records.", drivers.size());
            
        } catch (Exception e) {
            logger.error("#parse() - Finishing parsing file with errors.", e);
        }
        
        result.put("drivers", drivers);
        if (CollectionUtils.isNotEmpty(uploadResults)) {
            result.put("uploadResults", uploadResults);
        }
        
        return result;
        
    }
    
    /**
     * @param rowNum
     * @param driver
     * @return
     */
    private UploadResult checkRequiredField(int rowNum, Driver driver) {
        
        if (StringUtils.isBlank(driver.getCode())) {
            return new UploadResult(rowNum, "司机工号填写与模板不符");
        } else if (StringUtils.isBlank(driver.getCitizenCode())) {
            return new UploadResult(rowNum, "司机身份证号填写与模板不符");
        } else if (StringUtils.isBlank(driver.getName())) {
            return new UploadResult(rowNum, "司机姓名填写与模板不符");
        } else if (driver.getBirthday() == null) {
            return new UploadResult(rowNum, "司机出生日期填写与模板不符");
        } else if (StringUtils.isBlank(driver.getGender())) {
            return new UploadResult(rowNum, "司机性别填写与模板不符");
        } else if (StringUtils.isBlank(driver.getMp())) {
            return new UploadResult(rowNum, "司机手机号填写与模板不符");
        } else if (driver.getDutyId() == null) {
            return new UploadResult(rowNum, "司机职务填写与模板不符");
        } else if (driver.getDrivingAge() == null) {
            return new UploadResult(rowNum, "司机驾龄填写与模板不符");
        } else if (StringUtils.isBlank(driver.getContractParty())) {
            return new UploadResult(rowNum, "劳动合同签署方填写与模板不符");
        } else if (StringUtils.isBlank(driver.getDrivingType())) {
            return new UploadResult(rowNum, "主驾车型填写与模板不符");
        } else {
            return null;
        }
        
    }
    
    /**
     * @param driver
     * @param rowNum
     * @return
     */
    private UploadResult checkUniqueField(Driver driver, int rowNum) {
        
        Driver existDriver = driverDao.loadByCode(driver.getCode());
        if (existDriver != null) {
    		Supplier supplier = existDriver.getSupplier();
    		String supplierInfo = com.demo2do.core.utils.StringUtils.connect(supplier.getCode(), " - ", supplier.getName());
    		return new UploadResult(rowNum, "该司机工号已存在", supplierInfo);
        }
        
        existDriver = driverDao.loadByCitizen(driver.getCitizenCode());
        if (existDriver != null) {
    		Supplier supplier = existDriver.getSupplier();
        	String supplierInfo = com.demo2do.core.utils.StringUtils.connect(supplier.getCode(), " - ", supplier.getName());
            return new UploadResult(rowNum, "该司机身份证号已存在", supplierInfo);
        }
        
        existDriver = driverDao.loadByMobile(driver.getMp());
        if (existDriver != null) {
    		Supplier supplier = existDriver.getSupplier();
        	String supplierInfo = com.demo2do.core.utils.StringUtils.connect(supplier.getCode(), " - ", supplier.getName());
            return new UploadResult(rowNum, "该司机手机号已存在", supplierInfo);
        }
        
        return null;
        
    }

}
